Improve transformed offscreen rendering
authorMatthias Clasen <mclasen@redhat.com>
Thu, 13 May 2021 21:32:52 +0000 (17:32 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Thu, 13 May 2021 23:37:16 +0000 (19:37 -0400)
Preserve the scale for 2D transforms to
avoid a pixellated appearance.

gsk/ngl/gsknglrenderjob.c

index e23d4741c662ea494440a70c26f3fbf7732333fb..d08d45a04fee013d4d240b418a39e35a74d611a5 100644 (file)
@@ -524,7 +524,7 @@ gsk_ngl_render_job_push_modelview (GskNglRenderJob *job,
                              GskNglRenderModelview,
                              job->modelview->len - 2);
 
-      /* Multiply given matrix with our previews modelview */
+      /* Multiply given matrix with our previous modelview */
       t = gsk_transform_translate (gsk_transform_ref (last->transform),
                                    &(graphene_point_t) {
                                      job->offset_x,
@@ -1972,6 +1972,7 @@ gsk_ngl_render_job_visit_transform_node (GskNglRenderJob     *job,
       else
         {
           GskNglRenderOffscreen offscreen = {0};
+          float sx = 1, sy  = 1;
 
           offscreen.bounds = &child->bounds;
           offscreen.force_offscreen = FALSE;
@@ -1980,15 +1981,37 @@ gsk_ngl_render_job_visit_transform_node (GskNglRenderJob     *job,
           if (!result_is_axis_aligned (transform, &child->bounds))
             offscreen.linear_filter = TRUE;
 
+          if (category == GSK_TRANSFORM_CATEGORY_2D)
+            {
+              graphene_matrix_t m;
+              double a, b, c, d, tx, ty;
+
+              g_assert (transform != NULL);
+              gsk_transform_to_matrix (transform, &m);
+              if (graphene_matrix_to_2d (&m, &a, &b, &c, &d, &tx, &ty))
+                {
+                  sx = sqrt (a * a + b * b);
+                  sy = sqrt (c * c + d * d);
+                }
+              else
+                sx = sy = 1;
+
+              if (sx != 1 || sy != 1)
+                {
+                  GskTransform *scale;
+
+                  scale = gsk_transform_translate (gsk_transform_scale (NULL, sx, sy), &GRAPHENE_POINT_INIT (tx, ty));
+                  gsk_ngl_render_job_push_modelview (job, scale);
+                  transform = gsk_transform_transform (gsk_transform_invert (scale), transform);
+                }
+            }
+
           if (gsk_ngl_render_job_visit_node_with_offscreen (job, child, &offscreen))
             {
               /* For non-trivial transforms, we draw everything on a texture and then
                * draw the texture transformed. */
-              /* TODO: We should compute a modelview containing only the "non-trivial"
-               *       part (e.g. the rotation) and use that. We want to keep the scale
-               *       for the texture.
-               */
-              gsk_ngl_render_job_push_modelview (job, transform);
+              if (transform)
+                gsk_ngl_render_job_push_modelview (job, transform);
 
               gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit));
               gsk_ngl_program_set_uniform_texture (job->current_program,
@@ -1999,7 +2022,17 @@ gsk_ngl_render_job_visit_transform_node (GskNglRenderJob     *job,
               gsk_ngl_render_job_draw_offscreen (job, &child->bounds, &offscreen);
               gsk_ngl_render_job_end_draw (job);
 
-              gsk_ngl_render_job_pop_modelview (job);
+              if (transform)
+                gsk_ngl_render_job_pop_modelview (job);
+            }
+
+          if (category == GSK_TRANSFORM_CATEGORY_2D)
+            {
+              if (sx != 1 || sy != 1)
+                {
+                  gsk_ngl_render_job_pop_modelview (job);
+                  gsk_transform_unref (transform);
+                }
             }
         }
     break;